# from web_backend.sacem.services.TrainFirmwareService import get_firmware_version
from datetime import date
import datetime
import csv
import json
from backend.cews.services import PartsService
from django.apps import apps
from backend.cews.models import StockItem, Log, Parts, StockItemRelation
from django.db import transaction
from io import StringIO
import re

class Echo(object):
    def write(self, value):
        return value
    
def getCSVWriter():
    CSVWriter = csv.writer(Echo())
    return CSVWriter

def queryStockItemList():
    MyModel = apps.get_model('cews', 'StockItem')

    headers = [field.verbose_name.title() for field in MyModel._meta.get_fields() ]
    print("headers", headers)
    return 

def import_stock_item_list(csvfile, username):

    stock_list = csv.DictReader(StringIO(csvfile.file.read().decode()))
    data = list(stock_list)
    row = data[0]

    stock_dict = {
        s.stock_code: s
        for s in StockItem.objects.filter(deleted=False)
    }

    # if 'id' not in row or\
    # 'create' not in row or\
    if  'stock_code' not in row or\
        'system' not in row or\
        'car' not in row or\
        'workgroup' not in row or\
        'description' not in row or\
        'date_code' not in row or\
        'sw_ver' not in row or\
        'hw_ver' not in row or\
        'asset_id' not in row or\
        'equipment_class' not in row or\
        'lv1' not in row or\
        'lv2' not in row or\
        'lv3' not in row or\
        'lv4' not in row or\
        'lv5' not in row or\
        'detail_description' not in row :
        raise ValueError('Header Format incorrect')
    
    pattern = r'^(S\d{9}|\d{9})$'
    
    create_stocks = []
    update_stocks = []
    create_logs = []

    with transaction.atomic():
        try:
            for d in data:
                # if d['stock_code'].upper() in check_duplicate:
                #     raise ValueError(f"{d['stock_code'].upper()} is duplicate, please check")
                # else :
                #     check_duplicate[d['stock_code'].upper()] = 0

                if not re.match(pattern, d['stock_code'].upper()):
                    raise ValueError(f"{d['stock_code'].upper()} pattern wrong ,Stock Code must be in format 9 numbers or S + 9 numbers")
                
                s = stock_dict.get(d['stock_code'])
                if s and d['stock_code'] in stock_dict:
                    update = False
                    if s.workgroup !=d['workgroup'] or \
                            s.system !=d['system'] or \
                            s.description !=d['description'] or \
                            s.detail_description !=d['detail_description'] or \
                            s.date_code !=d['date_code'] or \
                            s.sw_ver !=d['sw_ver'] or \
                            s.hw_ver !=d['hw_ver'] or \
                            s.asset_id !=d['asset_id'] or \
                            s.equipment_class !=d['equipment_class'] or \
                            s.lv1 !=d['lv1'] or \
                            s.lv2 !=d['lv2'] or \
                            s.lv3 !=d['lv3'] or \
                            s.lv4 !=d['lv4'] or \
                            s.lv5 !=d['lv5']:
                        
                        update = True
                    
                    if update:
                        s.workgroup = d['workgroup']
                        s.system = d['system']
                        s.description = d['description']
                        s.detail_description = d['detail_description']
                        s.date_code = d['date_code']
                        s.sw_ver = d['sw_ver']
                        s.hw_ver = d['hw_ver']
                        s.asset_id = d['asset_id']
                        s.equipment_class = d['equipment_class']
                        s.lv1 = d['lv1']
                        s.lv2 = d['lv2']
                        s.lv3 = d['lv3']
                        s.lv4 = d['lv4']
                        s.lv5 = d['lv5']
                        # update_stocks.append(s)

                        if s.is_parent:
                            parent_stock_code = d['stock_code']
                            stock_code = ''
                        else:
                            parent_stock_code = ''
                            stock_code = d['stock_code']

                        update_log = Log(
                            username=username,
                            log_type=Log.LogType.STOCKMASTER,
                            category_type=Log.CategoryType.STOCK,
                            action_type=Log.ActionType.UPDATE,
                            action='update_s_by_import_csv',
                            payload= json.dumps(d),
                            description=f"Stock code: {s.stock_code}, description: {s.description} is updated",
                            repair_order=0,
                            parent_stock_code=parent_stock_code,
                            parent_part='',
                            part='',
                            stock_code=stock_code
                        )
                        s.save()
                        create_logs.append(update_log)

                        continue
                    continue

                stock_item =  StockItem(
                    stock_code=d['stock_code'].upper(),
                    workgroup=d['workgroup'],
                    system=d['system'],
                    description=d['description'],
                    detail_description=d['detail_description'],
                    date_code=d['date_code'],
                    sw_ver=d['sw_ver'],
                    hw_ver=d['hw_ver'],
                    asset_id=d['asset_id'],
                    equipment_class=d['equipment_class'],
                    lv1=d['lv1'],
                    lv2=d['lv2'],
                    lv3=d['lv3'],
                    lv4=d['lv4'],
                    lv5=d['lv5']
                )

                if stock_item.is_parent:
                    parent_stock_code = d['stock_code']
                    stock_code = ''
                else:
                    parent_stock_code = ''
                    stock_code = d['stock_code']

                new_log = Log(
                    username=username,
                    log_type=Log.LogType.STOCKMASTER,
                    category_type=Log.CategoryType.STOCK,
                    action_type=Log.ActionType.CREATE,
                    action='create_stock_item_by_import_csv',
                    payload= json.dumps(d),
                    description=f"Stock code: {stock_item.stock_code}, description: {stock_item.description} is created",
                    repair_order=0,
                    parent_stock_code=parent_stock_code,
                    parent_part='',
                    part='',
                    stock_code=stock_code
                )
                # create_stocks.append(stock_item)
                stock_item.save()
                create_logs.append(new_log)
            
            # print(create)
            # StockItem.objects.bulk_create(create_stocks)
            # StockItem.objects.bulk_update(update_stocks,[
            #     'workgroup',
            #     'system',
            #     'description',
            #     'detail_description',                                    
            #     'date_code',
            #     'sw_ver',
            #     'hw_ver',
            #     'asset_id',
            #     'equipment_class',
            #     'lv1',
            #     'lv2',
            #     'lv3',
            #     'lv4',
            #     'lv5',
            #     ])
            Log.objects.bulk_create(create_logs)

            return True
        except:
            print('Fail import')
            return False


def import_parts_master(csvfile, username):

    parts_list = csv.DictReader(StringIO(csvfile.file.read().decode()))
    data = list(parts_list)
    row = data[0]

    if'stock_code' not in row or 'serial_no' not in row:
        raise ValueError('Header Format incorrect')
    
    stock_dict = {
        s.stock_code: s
        for s in StockItem.objects.filter(deleted=False)
    }

    part_dict = {
        p.stock_code+p.serial_no: p
        for p in Parts.objects.filter(deleted=False)
    }

    create_parts = []
    update_parts = []

    create_log = []
    pattern = r'^(S\d{9}|\d{9})$'
    

    with transaction.atomic():
 
            for d in data:
                if d['stock_code'] not in stock_dict:
                    raise ValueError(f"SC: {d['stock_code'].upper()} has not been created in Stock Master")

                if not re.match(pattern, d['stock_code'].upper()):
                    raise ValueError(f"{d['stock_code'].upper()} pattern wrong ,Stock Code must be in format 9 numbers or S + 9 numbers")
                
                if d['obsolescence'].upper() != 'YES' and d['obsolescence'].upper() != 'NO':
                    raise ValueError(f"Obsolescence should be YES or NO {d['stock_code'].upper()}, SN: {d['serial_no']} ")

                if d['obsolescence'].upper() == 'YES':            
                    obsolescence = 1

                if d['obsolescence'].upper() == 'NO':            
                    obsolescence = 0

                part_key = d['stock_code'].upper() + d['serial_no']

                old_p = part_dict.get(part_key)

                if old_p and part_key in part_dict:
                    update = False
                    if  old_p.date_code != d['date_code'] or \
                        old_p.sw_ver != d['sw_ver'] or \
                        old_p.hw_ver != d['hw_ver'] or \
                        old_p.obsolescence != obsolescence:
                        update = True
                        # old_p.location !=d['location'] or \

                    if update:
                        # old_p.location = d['location']
                        old_p.date_code = d['date_code']
                        old_p.sw_ver = d['sw_ver']
                        old_p.hw_ver = d['hw_ver']
                        old_p.obsolescence = obsolescence

                        old_parent_stock_code=''
                        old_parent_serial_no=''
                        old_stock_code=''
                        old_serial_no=''

                        if old_p.is_parent:
                            old_parent_stock_code = old_p.stock_code
                            old_parent_serial_no = old_p.serial_no
                        else:
                            old_stock_code = old_p.stock_code
                            old_serial_no = old_p.serial_no

                        update_log = Log(
                            username=username,
                            log_type=Log.LogType.PARTMASTER,
                            category_type=Log.CategoryType.PART,
                            action_type=Log.ActionType.UPDATE,
                            action='update_parts_by_import_csv',
                            payload= json.dumps(d),
                            description=f"SC: {old_p.stock_code}, SN: {old_p.serial_no}, description: {old_p.description} is updated",
                            repair_order=0,
                            parent_stock_code=old_parent_stock_code,
                            parent_part=old_parent_serial_no,
                            part=old_serial_no,
                            stock_code=old_stock_code
                        )
                        old_p.save()
                        create_log.append(update_log)
                        # update_parts.append(old_p)
                        continue
                    PartsService.create_part_replacement(old_p)
                    continue

                key = d['stock_code']
                parent_stock_code = str(d['parent_stock_code'])
                parent_serial_no = str(d['parent_serial_no'])
                sequence = int(d['sequence'])
                ok_sequence = 0
                parent = None

                if parent_stock_code != '' and parent_serial_no !='':
                    parents = Parts.objects.filter(stock_code=parent_stock_code, serial_no=parent_serial_no,deleted=False)
                    if parents.exists():
                        parent = Parts.objects.get(stock_code=parent_stock_code, serial_no=parent_serial_no,deleted=False)
                    else:
                        raise ValueError(f"Parent Part: {parent_stock_code}, {parent_serial_no} not exist")
                    
                    sir = StockItemRelation.objects.filter(child__stock_code=key, parent__stock_code=parent.stock_code, sequence=sequence)

                    if sir.exists():  
                        s_r = StockItemRelation.objects.get(child__stock_code=key, parent__stock_code=parent.stock_code,sequence=sequence)
                        ok_sequence = s_r.sequence
                    else:
                        raise ValueError(f"Relation of parent: {parent_stock_code}, child: {key}, sequence: {sequence} wrong")
                print('parent', parent)
                print('ok_sequence', ok_sequence)
                new_p = Parts(
                    stock_code=d['stock_code'],
                    serial_no=d['serial_no'],
                    system=stock_dict[key].system,
                    # location=d['location'],
                    workgroup=stock_dict[key].workgroup,
                    description=stock_dict[key].description,
                    detail_description=stock_dict[key].detail_description,
                    date_code=d['date_code'],
                    sw_ver=d['sw_ver'],
                    hw_ver=d['hw_ver'],
                    asset_id=stock_dict[key].asset_id,
                    equipment_class=stock_dict[key].equipment_class,
                    lv1=stock_dict[key].lv1,
                    lv2=stock_dict[key].lv2,
                    lv3=stock_dict[key].lv3,
                    lv4=stock_dict[key].lv4,
                    lv5=stock_dict[key].lv5,
                    obsolescence=obsolescence,
                    parent_part=parent,
                    sequence=ok_sequence
                )

                new_parent_stock_code=''
                new_parent_serial_no=''
                new_stock_code=''
                new_serial_no=''

                if new_p.is_parent:
                    new_parent_stock_code = new_p.stock_code
                    new_parent_serial_no = new_p.serial_no
                else:
                    new_stock_code = new_p.stock_code
                    new_serial_no = new_p.serial_no

                new_log = Log(
                    username=username,
                    log_type=Log.LogType.PARTMASTER,
                    category_type=Log.CategoryType.PART,
                    action_type=Log.ActionType.CREATE,
                    action='create_parts_by_import_csv',
                    payload= json.dumps(d),
                    description=f"SC: {new_p.stock_code}, SN: {new_p.serial_no}, description: {new_p.description} is created",
                    repair_order=0,
                    parent_stock_code=new_parent_stock_code,
                    parent_part=new_parent_serial_no,
                    part=new_serial_no,
                    stock_code=new_stock_code
                )
                new_p.save()
                PartsService.create_part_replacement(new_p)
                # create_parts.append(new_p)
                create_log.append(new_log)

        # except Exception as error:
        #     print('Import fail', error)
        #     return False
    # Parts.objects.bulk_create(create_parts)
    # Parts.objects.bulk_update(update_parts,['date_code','sw_ver','hw_ver','obsolescence'])
    Log.objects.bulk_create(create_log)
    return True